﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Http;
using System.Web.Http.Filters;

namespace Base.Common.httpServer {
    /**
   *┌────────────────────────────────────────────────┐
   *│　描    述：Fade                                                    
   *│　作    者：sgj                                              
   *│　版    本：1.0                                              
   *│　创建时间：2020/10/19 12:58:20                        
   *└────────────────────────────────────────────────┘
   **/
    public class HttpApiFacade {
          static Dictionary<String ,List<HttpMethod>> classDictionary = new Dictionary<String ,List<HttpMethod>>();
         static public HttpParam getAction(String path) {
             int index = path.Substring(1).IndexOf("/");
            String classNameUrl = null;
            if( index == -1 ) {
                classNameUrl = path;
            } else {
                classNameUrl = path.Substring(0 ,index + 1);
            }
             classNameUrl = classNameUrl.ToLower();
             HttpParam p = selectParam(path ,classNameUrl);
            if( p == null ) {
                p = selectParam(path ,"/");
            }
            return p;
          }
          static HttpParam selectParam(String path ,String  root) {
            if(! classDictionary.ContainsKey(root) ) {
                return null;
            }
            List<HttpMethod>  mathDictionary = classDictionary[root];
            foreach( HttpMethod item in mathDictionary ) {
                if( Regex.IsMatch(path ,item.path ,RegexOptions.IgnoreCase) ) {
                    Match mc = Regex.Match(path ,item.path,RegexOptions.Multiline | RegexOptions.IgnoreCase);
                    GroupCollection mg = mc.Groups;
                    Dictionary<String ,object> paramDict = new Dictionary<string ,object>();
                    for( int i = 0;i < mg.Count-1;i++ ) {
                       
                        var value = mg[i+1];
                        List<String> uriParamKey = item.uriParamKey;
                        if( i < uriParamKey.Count ) {
                            String param = value.ToString();
                            if (!String.IsNullOrEmpty(param) && param.Length > 1)
                            {
                                paramDict.Add(uriParamKey[i], param.Substring(1));
                            }
                            else {
                                paramDict.Add(uriParamKey[i], "");
                            }
                          
                        }
                     }
                    return new HttpParam() { mc = paramDict ,meth = item };
                }
            }
            return null;
         }
          static public void initTypes() {
            if( classDictionary.Count != 0 ) {
                return;
            }
             Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
            foreach( Assembly asm in ass ) {
                AssemblyName name = asm.GetName();
               byte[] b= name.GetPublicKeyToken();
                if( b.Length != 0 ) {
                    continue;
                }
                Type[] ts = asm.GetTypes();
                foreach( var t in ts ) {
                    addHttpMethod(t);
                }
             }
        }
         static void addHttpMethod(Type t) {
            if( !t.IsClass ) {
                return;
            }
            if( !t.IsSubclassOf(typeof(BaseApiController)) ) {
                return;
            }
          
            RoutePrefixAttribute a = ( RoutePrefixAttribute ) Attribute.GetCustomAttribute(t ,typeof(RoutePrefixAttribute));
            AuthorizationFilterAttribute authorization = ( AuthorizationFilterAttribute ) Attribute.GetCustomAttribute(t ,typeof(AuthorizationFilterAttribute));
            
            String basePath = "";
            String key = "";
            if( a != null ) {
                basePath = a.Prefix;
                int index = basePath.IndexOf("/");
                if( index == -1 ) {
                    key ="/"+ basePath;
                } else {
                    key = "/" + basePath.Substring(0 ,index);
                }
                basePath = "/" + basePath;
             } else {
                basePath = "";
                key = "/";
            }
            
             if( !classDictionary.ContainsKey(key.ToLower()) ) {
                classDictionary.Add(key.ToLower() ,new List<HttpMethod>());
            }
            Object server = ( Object ) Activator.CreateInstance(t);
            MethodInfo[] mis = t.GetMethods();
            foreach( MethodInfo mi in mis ) {
                RouteAttribute b = ( RouteAttribute ) Attribute.GetCustomAttribute(mi ,typeof(RouteAttribute));
                if( b == null ) {
                    continue;
                }
                String uri = basePath + "/" + b.Template;
                 classDictionary[key.ToLower()].Add(new HttpMethod(uri ,server ,mi,authorization!=null));
             }
        }
     }
     public class HttpParam {
        public Dictionary<String ,object> mc;//实际参数
         Object getValue(String key) {
            if( mc.ContainsKey(key) ) {
                return mc[key];
            } else {
                return null;
            }
        }
        public HttpMethod meth;
        public Object doAction() {
           
            int len = meth.parameterInfos.Length;
            Object[] param = new Object[len];
             for( int i = 0;i < len;i++ ) {
                 ParameterInfo pi = meth.parameterInfos[i];
                String key = pi.Name.ToString();
                if( pi.ParameterType == typeof(long) ) {
                  
                    param[i] = Convert.ToInt64(getValue(key));
                }else if (pi.ParameterType == typeof(int))
                {
                     param[i] = Convert.ToInt32(getValue(key));
                }
                else {
                    param[i] = getValue(key);
                }
             }
            return meth.method.Invoke(meth.server ,param);//执行
         }
    }
     public class HttpMethod {
        public String path;
        public bool authorization;
        public ControlName controlName;
        public Object server;
        public MethodInfo method;
        public ParameterInfo[] parameterInfos;
        public ParameterInfo body;
        public List<String> uriParamKey = new List<string>();
           public HttpMethod(String path1 ,Object server ,MethodInfo meth,bool authorization) {
            this.path = path1;
            this.method = meth;
            this.server = server;
            this.authorization = authorization;


            controlName = ( ControlName ) Attribute.GetCustomAttribute(method ,typeof(ControlName));
             MatchCollection mc = Regex.Matches(path ,@"/\{\w+\??\}");
            foreach( var key in mc ) {
                String v = key.ToString();
                int length= v.Length-2;
                if (v.IndexOf("?")==-1) {
                    length-=1;
                }
                else {
                    length -= 2;
                }
             
                uriParamKey.Add(v.Substring(2, length));
                 path = path.Replace(v , @"(/[\w!-.0-`]*)?");
             }
            this.path = "^" + this.path + "$";
        
            //LoggerCommon.consol("init:" + path);
             parameterInfos = method.GetParameters();
             foreach( ParameterInfo info in parameterInfos ) {
                
                FromBodyAttribute b = ( FromBodyAttribute ) Attribute.GetCustomAttribute(info ,typeof(FromBodyAttribute));
                Type type = info.ParameterType;
                if( type != typeof( String) && type.IsClass ) {
                    if( body != null ) {
                        throw new Exception("参数异常");
                    }
                    body = info;
                }
             }
         }
      }
  }
